package org.stbernardpreserve.learning.effectivejava.hashcodeequalstostring;

import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.*;

import org.junit.Test;
import org.stbernardpreserve.learning.effectivejava.hashcodeequalstostring.ApacheDog.IllegalDogStateException;

public class ApacheDogTestEqualsHashCodeAndToString {

	@Test
	public void testWeightValidation() {
		try {
			new ApacheDog.DogBuilder().age(8).breed(ApacheDog.Breed.STBERNARD)
					.name("Pearl").droolCoefficient(.75).build();
		} catch (IllegalDogStateException e) {
			return;
		}

		assertTrue("Failed to validate Dog", false);
	}

	@Test
	public void testAgeValidation() {
		try {
			new ApacheDog.DogBuilder().weight(208)
					.breed(ApacheDog.Breed.STBERNARD).name("Pearl")
					.droolCoefficient(.75).build();
		} catch (IllegalDogStateException e) {
			return;
		}

		assertTrue("Failed to validate Dog", false);
	}

	@Test
	public void testBreedValidation() {
		try {
			new ApacheDog.DogBuilder().weight(208).age(8).name("Pearl")
					.droolCoefficient(.75).build();
		} catch (IllegalDogStateException e) {
			return;
		}

		assertTrue("Failed to validate Dog", false);
	}

	@Test
	public void testToString() {
		ApacheDog bernard = new ApacheDog.DogBuilder().weight(208).age(8)
				.breed(ApacheDog.Breed.STBERNARD).name("Pearl")
				.droolCoefficient(.75).build();

		assertThat(
				"Returned ToString is Correct",
				bernard.toString(),
				is("[breed=St. Bernard,name=Pearl,age=8,weight=208,droolWeight=heavy]"));

	}

	@Test
	public void testEquals() {
		ApacheDog bernard = new ApacheDog.DogBuilder().weight(208).age(8)
				.breed(ApacheDog.Breed.STBERNARD).name("Pearl")
				.droolCoefficient(.75).build();

		ApacheDog rottweiler = new ApacheDog.DogBuilder().weight(95).age(5)
				.breed(ApacheDog.Breed.ROTTWEILER).name("George")
				.droolCoefficient(.20).build();

		assertFalse("Bernard Doesn't equal rottweiler",
				bernard.equals(rottweiler));

		// Reflexive
		assertTrue("Bernard Equals itself", bernard.equals(bernard));

		ApacheDog bernard2 = new ApacheDog.DogBuilder().weight(208).age(8)
				.breed(ApacheDog.Breed.STBERNARD).name("Jack")
				.droolCoefficient(.75).build();

		// Symetric
		assertTrue("Bernard Equals Bernard2", bernard.equals(bernard2));
		assertTrue("Bernard2 Equals Bernard", bernard2.equals(bernard));

		ApacheDog bernard3 = new ApacheDog.DogBuilder().weight(208).age(8)
				.breed(ApacheDog.Breed.STBERNARD).name("Phred")
				.droolCoefficient(.35).build();

		// Transitive
		assertTrue("Bernard Equals Bernard2", bernard.equals(bernard2));
		assertTrue("Bernard Equals Bernard3", bernard.equals(bernard3));
		assertTrue("Bernard2 Equals Bernard3", bernard2.equals(bernard3));

		// Consistent
		assertTrue("Bernard Equals Bernard2", bernard.equals(bernard2));
		assertTrue("Bernard2 Equals Bernard", bernard2.equals(bernard));
		assertTrue("Bernard Equals Bernard2", bernard.equals(bernard2));
		assertTrue("Bernard2 Equals Bernard", bernard2.equals(bernard));

		// null values
		assertFalse("Bernard Equals Bernard2", bernard.equals(null));

	}

	@Test
	public void testHashCode() {
		ApacheDog bernard = new ApacheDog.DogBuilder().weight(208).age(8)
				.breed(ApacheDog.Breed.STBERNARD).name("Pearl")
				.droolCoefficient(.75).build();
		ApacheDog bernard2 = new ApacheDog.DogBuilder().weight(208).age(8)
				.breed(ApacheDog.Breed.STBERNARD).name("Jack")
				.droolCoefficient(.75).build();

		assertTrue("Bernard equals bernard2", bernard.equals(bernard2));
		assertThat("Bernard HashCode equals Bernard2 Hashcode",
				bernard.hashCode(), is(bernard2.hashCode()));

		ApacheDog rottweiler = new ApacheDog.DogBuilder().weight(95).age(5)
				.breed(ApacheDog.Breed.ROTTWEILER).name("George")
				.droolCoefficient(.20).build();

		assertFalse("Bernard Doesn't equal rottweiler",
				bernard.equals(rottweiler));
		assertThat("Bernard hashCode Doesn't equal rottweiler hashcode",
				bernard.hashCode(), not(rottweiler.hashCode()));

		ApacheDog oldEnglishMastiff = new ApacheDog.DogBuilder().weight(225)
				.age(3).breed(ApacheDog.Breed.OLD_ENGLISH_MASTIFF)
				.name("Buddy").droolCoefficient(.5).build();

		assertFalse("Bernard Doesn't equal old english mastiff",
				bernard.equals(oldEnglishMastiff));
		assertThat(
				"Bernard hashCode Doesn't equal old english mastiff hashcode",
				bernard.hashCode(), not(oldEnglishMastiff.hashCode()));
	}

}
